package com.zhmsky.config.shiro;

import com.zhmsky.filter.JwtFilter;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;

/**
 * @author zhmsky
 * @date 2021/12/5 11:00
 */
@Configuration
public class ShiroConfig {
    /**
     * @param defaultWebSecurityManager
     * @return
     * @description 除未授权路径外其他所有请求均通过自定义过滤器，如果请求头中携带Token，则用Token去login，去realm验证
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //使用自定义的过滤器，让所有请求均通过我们的过滤器(不使用shiro内置过滤器)
        LinkedHashMap<String, Filter> filterMap = new LinkedHashMap<>();
        //添加自定义的过滤器且取名为 jwt
        filterMap.put("jwt", new JwtFilter());
        //添加自定义的过滤器
        shiroFilterFactoryBean.setFilters(filterMap);
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //设置无权限时跳转的路径
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized/无权限");

        HashMap<String, String> ruleMap = new HashMap<>();
        //设置所有请求通过自定义的jwt过滤器
        ruleMap.put("/**", "jwt");
        //访问未授权路径时无需认证
        ruleMap.put("/unauthorized/**", "anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(ruleMap);
        return shiroFilterFactoryBean;
        /*
           anon: 无需认证就可以访问
           authc: 必须认证才能访问
           user: 必须拥有 记住我 才能被访问
           perms: 拥有对某个资源的权限才能被访问
           role: 拥有某个角色权限才能被访问
         */

    }

    //DefaultWebSecurityManager 管理realm对象
    @Bean
    public DefaultWebSecurityManager getWebSecurityManager(UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm对象
        securityManager.setRealm(userRealm);
        /*
         * 关闭shiro自带的session，详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);

        return securityManager;
    }

    /**
     * @description 添加注解支持
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib，防止重复代理和可能引起代理出错的问题
        // https://zhuanlan.zhihu.com/p/29161098
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
}
